﻿using System.Collections.Generic;
using System.IO;
using System.Xml;
using CodePlex.TeamFoundation.Adapters;
using CodePlex.TeamFoundation.Adapters.WorkItemTracking;
using Microsoft.TeamFoundation.Build.Client;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;

namespace CodePlex.TeamFoundation.Utilities.Test
{


  /// <summary>
  ///This test class contains all the unit tests for 
  ///CodePlex.TeamFoundation.Utilities.BuildUtilities
  ///implemented using the Moq framework.
  ///</summary>
  [TestClass()]
  public class MoqBuildUtilitiesTests
  {


    private TestContext testContextInstance;

    /// <summary>
    ///Gets or sets the test context which provides
    ///information about and functionality for the current test run.
    ///</summary>
    public TestContext TestContext
    {
      get
      {
        return testContextInstance;
      }
      set
      {
        testContextInstance = value;
      }
    }

    #region Additional test attributes
    // 
    //You can use the following additional attributes as you write your tests:
    //
    //Use ClassInitialize to run code before running the first test in the class
    //[ClassInitialize()]
    //public static void MyClassInitialize(TestContext testContext)
    //{
    //}
    //
    //Use ClassCleanup to run code after all tests in a class have run
    //[ClassCleanup()]
    //public static void MyClassCleanup()
    //{
    //}
    //
    //Use TestInitialize to run code before running each test
    //[TestInitialize()]
    //public void MyTestInitialize()
    //{
    //}
    //
    //Use TestCleanup to run code after each test has run
    //[TestCleanup()]
    //public void MyTestCleanup()
    //{
    //}
    //
    #endregion

    /// <summary>
    ///A test for UpdateWorkItem
    ///Change Active state to Resolved
    ///</summary>
    [TestMethod()]
    public void MoqUpdateWorkItemsForBuildActiveStateTest()
    {
      StreamReader sr = new StreamReader("BuildCompletionEventSample.xml");
      string eventXML = sr.ReadToEnd();
      string transitionFromState = "Active";
      string transitionToState = "Resolved";
      UpdateWorkItemTest(eventXML, transitionFromState, transitionToState);
    }

    /// <summary>
    ///A test for UpdateWorkItem
    ///Change state to Resolved for all work items
    ///</summary>
    [TestMethod()]
    public void MoqUpdateWorkItemsForBuildEmptyStateTest()
    {
      StreamReader sr = new StreamReader("BuildCompletionEventSample.xml");
      string eventXML = sr.ReadToEnd();
      string transitionFromState = string.Empty;
      string transitionToState = "Resolved";
      UpdateWorkItemTest(eventXML, transitionFromState, transitionToState);
    }

    /// <summary>
    /// This method does all the heavy lifting for the UpdateWorkItemsForBuild tests
    /// </summary>
    /// <param name="EventXml"></param>
    /// <param name="transitionFromState"></param>
    /// <param name="transitionToState"></param>
    private void UpdateWorkItemTest(string eventXml, string transitionFromState, string transitionToState)
    {
      // Extract build URI and build number from BuildCompletionEvent eventXml
      XmlDocument doc = new XmlDocument();
      doc.LoadXml(eventXml);
      System.Uri buildUri = GetBuildUri(doc);
      string buildNumber = GetBuildNumber(doc);

      // Setup IBuildDetail mock object
      var buildDetailMock = new Mock<IBuildDetail>();
      buildDetailMock.SetupProperty(x => x.BuildNumber);
      IBuildDetail buildDetailMockObject = (IBuildDetail)buildDetailMock.Object;
      buildDetailMockObject.BuildNumber = buildNumber;

      // Setup IBuildServer mock object
      var buildServerMock = new Mock<IBuildServer>();
      buildServerMock.Setup(x => x.GetAllBuildDetails(buildUri)).Returns(buildDetailMockObject);
      IBuildServer buildServerMockObject = (IBuildServer)buildServerMock.Object;

      // Setup WorkItem mock object
      var workItemMock = new Mock<IWorkItem>();
      workItemMock.SetupProperty(x => x.State);
      //workItemMock.SetupProperty(x => x.History);
      workItemMock.Setup(x => x.Save()).Verifiable();
      IWorkItem workItemMockObject = (IWorkItem)workItemMock.Object;
      workItemMockObject.State = "Active";
      //workItemMockObject.History = string.Format("Build {0} changed state from {1} to {2}", buildNumber, workItemMockObject.State, transitionToState);

      // Setup WorkItemSummary mock object
      int mockWorkItemID = 123;
      var workItemSummaryMock = new Mock<IWorkItemSummary>();
      workItemSummaryMock.Setup(x => x.WorkItemId).Returns(mockWorkItemID);
      IWorkItemSummary workItemSummaryMockObject = (IWorkItemSummary)workItemSummaryMock.Object;

      // Setup WorkItemStore mock object
      var workItemStoreMock = new Mock<IWorkItemStore>();
      workItemStoreMock.Setup(x => x.GetWorkItem(mockWorkItemID)).Returns(workItemMockObject);
      IWorkItemStore workItemStoreMockObject = workItemStoreMock.Object;

      // Setup TfsFactory mock object
      var tfsFactoryMock = new Mock<ITfsFactory>();
      tfsFactoryMock.Setup(x => x.GetWorkItemStore()).Returns(workItemStoreMockObject);
      tfsFactoryMock.Setup(x => x.GetBuildServer()).Returns(buildServerMockObject);
      List<IWorkItemSummary> associatedWorkItems = new List<IWorkItemSummary>();
      associatedWorkItems.Add(workItemSummaryMockObject);
      tfsFactoryMock.Setup(x => x.GetAssociatedWorkItems(buildDetailMockObject)).Returns(associatedWorkItems);
      ITfsFactory tfsFactoryMockObject = tfsFactoryMock.Object;

      // Run the test
      BuildUtilities target = new BuildUtilities();
      target.UpdateWorkItemsForBuild(tfsFactoryMockObject, eventXml, transitionFromState, transitionToState);
      Assert.AreEqual(transitionToState, workItemMockObject.State);
      workItemMock.VerifyAll();
    }

    private System.Uri GetBuildUri(XmlDocument eventXmlDocument)
    {
      // Extract buildUri and buildNumber from BuildCompletionEvent EventXml
      XmlNode idNode = eventXmlDocument.SelectSingleNode(@"//BuildCompletionEvent/Url");
      if (idNode == null)
        throw new System.ApplicationException("Sample BuildCompletionEvent eventXml is bad, Url not found");
      string buildUrl = idNode.InnerText;
      string buildMoniker = buildUrl.Substring(buildUrl.IndexOf("=") + 1);
      string buildUri = "vstfs:///Build/Build/" + buildMoniker;
      return new System.Uri(buildUri);
    }

    private string GetBuildNumber(XmlDocument eventXmlDocument)
    {
      // Extract buildUri and buildNumber from BuildCompletionEvent EventXml
      XmlNode idNode = eventXmlDocument.SelectSingleNode(@"//BuildCompletionEvent/Id");
      if (idNode == null)
        throw new System.ApplicationException("Sample BuildCompletionEvent eventXml is bad, Id not found");
      string buildNumber = idNode.InnerText;
      return buildNumber;
    }
  }
}
